package com.szwistar.common.comm.jsonrpc.udp;

import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.util.ArrayList;
import java.util.List;

import org.apache.mina.core.buffer.IoBuffer;

import com.szwistar.common.comm.blocktrans.BlockTransPayload;
import com.szwistar.common.datastruct.JsonMapper;

/**
 * JSON-RPC 请求
 */
public class JsonRpcRequest implements BlockTransPayload {
	// 帧类型 ID
	public static final short TYPEID = 0x1000;

	// 默认的 JSON 字符编解码器
	protected static final CharsetDecoder charsetDecoder = Charset.forName("UTF-8").newDecoder();
	protected static final CharsetEncoder charsetEncoder = Charset.forName("UTF-8").newEncoder();

	// 会话token(8字节)
	protected long token;
	// 命令序列号(2字节)
	protected short sn;

	// 目标对象(如果是静态方法，可以提供类名称或对象ID；如果是对象方法，必须提供对象ID)
	protected String target;
	// 目标方法
	protected String method;
	// 调用参数(JSON 格式参数数组，需按照方法对应的参数顺序放置)
	protected Object[] params;

	public JsonRpcRequest() {
	}

	/**
	 * 构造函数(从缓冲区中解码出来)
	 * @param in
	 * @throws Exception
	 */
	public JsonRpcRequest(IoBuffer in, int length) throws Exception {
		decode(in, length);
	}

	public JsonRpcRequest(long token, String target, String method, Object ...params) {
		this.token = token;
		this.sn = (short) (Math.random()*0xFFFF);
		this.target = target;
		this.method = method;
		this.params = params;
	}

	public JsonRpcRequest(long token, int oid, String method, Object ...params) {
		this(token, Integer.toString(oid), method, params);
	}

	@Override
	public short typeId() { return TYPEID; }

	public long getToken() {
		return token;
	}

	public void setToken(long token) {
		this.token = token;
	}

	public short getSn() {
		return sn;
	}

	public void setSn(short sn) {
		this.sn = sn;
	}

	public String getTarget() {
		return target;
	}

	public void setTarget(String target) {
		this.target = target;
	}

	public String getMethod() {
		return method;
	}

	public void setMethod(String method) {
		this.method = method;
	}

	public Object[] getParams() {
		return params;
	}

	public void setParams(Object[] params) {
		this.params = params;
	}

	/**
	 * 解码帧数据
	 * @throws Exception
	 */
	@Override
	@SuppressWarnings("unchecked")
	public void decode(IoBuffer in, int length) throws Exception {
		token = in.getLong();
		sn = in.getShort();

		String json = in.getString(length-10, charsetDecoder);
		List<Object> list = JsonMapper.fromJson(json, ArrayList.class);

		target = (String) list.get(0);
		method = (String) list.get(1);
		params = ((ArrayList<Object>)list.get(2)).toArray();
	}

	/**
	 * 把帧编码并放入缓冲区
	 * @param out
	 * @throws Exception
	 */
	@Override
	public void encode(IoBuffer out) throws Exception {
		out.putLong(token);
		out.putShort(sn);

		List<Object> body = new ArrayList<Object>();
		body.add(target);
		body.add(method);
		body.add(params);
		String json = JsonMapper.toJson(body);
		out.putString(json, charsetEncoder);
	}

	@Override
	public String toString() {
		try {
			return String.format("%s(token=%016X, sn=0x%04X, service='%s', method='%s', params='%s')",
					this.getClass().getSimpleName(),
					token, sn, target, method, JsonMapper.toJson(params));
		} catch (Exception e) {
			return super.toString();
		}
	}
}
